/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#include <iostream>

#include "HttpRequest.h"
#include "HttpResponse.h"
#include "X509TrustAll.h"

using aliyun::Exception;
using aliyun::http::MethodType;
using aliyun::http::FormatType;
using aliyun::http::HttpRequest;
using aliyun::http::HttpResponse;
using aliyun::http::X509TrustAll;

#define assertTrue(expr) do { \
  std::cerr << "assertTrue(" << #expr << "): "; \
  if(expr) { \
    std::cerr << "PASS!" << std::endl; \
  } else { \
    std::cerr << "FAIL!" << std::endl; \
    ::exit(-1); \
  } \
} while(0)

void printHttpResponse(HttpResponse response) {
#if 1
  std::cout << "RESPONSE STATUS:" << response.getStatus() << std::endl;
  std::cout << "RESPONSE HEADER:" << std::endl;
  for (std::map<std::string, std::string>::const_iterator it = response
      .getHeaders().begin(); it != response.getHeaders().end(); ++it) {
    std::cout << "\"" << it->first << "\" => \"" << it->second << "\"\n";
  }
  std::cout << "RESPONSE BODY:\n" << response.getContent() << std::endl;
#endif
}

void testHttpGet() {
  HttpRequest request("http://acs.aliyun-inc.com/");
  request.setMethod(MethodType::GET);
  request.putHeaderParameter("Accept", "*/*");
  request.putHeaderParameter(
      "User-Agent",
      "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36");
  try {
    HttpResponse response = HttpResponse::getResponse(request);

    printHttpResponse(response);
    assertTrue(response.getStatus() == 400);
    assertTrue(response.getContent().length() > 0);
  } catch (Exception& e) {
    std::cout << "\nException: " << e.what() << std::endl;
    std::cout << e.stackTrace() << std::endl;
  } catch (...) {
    std::cout << "unknow exceptions" << std::endl;
  }
  std::cout << __FUNCTION__ << "\nDONE\n" << std::endl;
}

void testHttpPut() {
  std::string content =
      "<Product name=\"Yundun\" domain=\"yundun.aliyuncs.com\"/>";
  HttpRequest request("http://acs.aliyun-inc.com/");
  request.setMethod(MethodType::PUT);
  try {
    request.setContent(content, "UTF-8", FormatType::XML);
    HttpResponse response = HttpResponse::getResponse(request);

    printHttpResponse(response);
    assertTrue(response.getStatus() == 400);
    assertTrue(response.getContent().length() > 0);
  } catch (Exception& e) {
    std::cout << "\nException: " << e.what() << std::endl;
    std::cout << e.stackTrace() << std::endl;
  } catch (...) {
    std::cout << "unknow exceptions" << std::endl;
  }
  std::cout << __FUNCTION__ << "\nDONE\n" << std::endl;
}

// DONE: add unit test for POST, etc
void testHttpPost() {
  // set up a web server on localhost
  std::string url =
      "http://203.88.161.174:8080/servlet/service?user=name&pass=word";
  HttpRequest request(url);

  try {
    request.setMethod(MethodType::POST);
    HttpResponse response = HttpResponse::getResponse(request);

    printHttpResponse(response);
    assertTrue(response.getHeaderValue("Request-Method") == "POST");  // servlet
    assertTrue(response.getContent().length() > 0);
  } catch (Exception& e) {
    std::cout << "\nException: " << e.what() << std::endl;
    std::cout << e.stackTrace() << std::endl;
  } catch (...) {
    std::cout << "unknow exceptions" << std::endl;
  }
  std::cout << __FUNCTION__ << "\nDONE\n" << std::endl;
}

void testHttpHead() {
  HttpRequest request("http://203.88.161.174:8080/servlet/service");
  try {
    request.setMethod(MethodType::HEAD);
    HttpResponse response = HttpResponse::getResponse(request);

    printHttpResponse(response);
    assertTrue(response.getHeaderValue("Request-Method") == "HEAD");  // servlet
    assertTrue(response.getContent().length() == 0);
  } catch (Exception& e) {
    std::cout << "\nException: " << e.what() << std::endl;
    std::cout << e.stackTrace() << std::endl;
  } catch (...) {
    std::cout << "unknow exceptions" << std::endl;
  }
  std::cout << __FUNCTION__ << "\nDONE\n" << std::endl;
}

void testHttpDelete() {
  HttpRequest request("http://203.88.161.174:8080/servlet/service");
  try {
    request.setMethod(MethodType::DELETE);
    HttpResponse response = HttpResponse::getResponse(request);

    printHttpResponse(response);
    assertTrue(response.getHeaderValue("Request-Method") == "DELETE");  // servlet
    assertTrue(response.getContent().length() > 0);
  } catch (Exception& e) {
    std::cout << "\nException: " << e.what() << std::endl;
    std::cout << e.stackTrace() << std::endl;
  } catch (...) {
    std::cout << "unknow exceptions" << std::endl;
  }
  std::cout << __FUNCTION__ << "\nDONE\n" << std::endl;
}

void testHttpOptions() {
  HttpRequest request("http://acs.aliyun-inc.com/");
  try {
    request.setMethod(MethodType::OPTIONS);
    HttpResponse response = HttpResponse::getResponse(request);

    printHttpResponse(response);
    //assertTrue(response.getHeaders()["Request-Method"] == "OPTIONS");
    assertTrue(response.getContent().length() == 0);
  } catch (Exception& e) {
    std::cout << "\nException: " << e.what() << std::endl;
    std::cout << e.stackTrace() << std::endl;
  } catch (...) {
    std::cout << "unknow exceptions" << std::endl;
  }
  std::cout << __FUNCTION__ << "\nDONE\n" << std::endl;
}

void testHttps() {
  HttpRequest reqest("https://acs.aliyun-inc.com/");
  try {
    X509TrustAll trustAll;  // SSL peer certificate or SSH remote key was not OK
    HttpResponse response = HttpResponse::getResponse(reqest);

    printHttpResponse(response);
    assertTrue(response.getStatus() == 400);
    assertTrue(response.getContent().length() > 0);
  } catch (Exception& e) {
    std::cout << "\nException: " << e.what() << std::endl;
    std::cout << e.stackTrace() << std::endl;
  } catch (...) {
    std::cout << "unknow exceptions" << std::endl;
  }
}

int main(int argc, char* argv[]) {
  testHttpGet();
  testHttpPut();
  testHttpPost();
  testHttpHead();
  testHttpDelete();
  testHttpOptions();
  testHttps();
  return 0;
}
